<template>
  <div>
    <button @click="insertTable(3, 3)">插入表格</button>
    <button @click="addColumn">添加列</button>
    <button @click="addRow">添加行</button>
    <button @click="deleteTable">删除表格</button>
    <button @click="mergeCells">合并单元格</button>
    <button @click="splitCell">拆分单元格</button>
    <button @click="deleteRow" :disabled="!canDeleteRow">删除行</button>
    <button @click="deleteColumn" :disabled="!canDeleteColumn">删除列</button>
    <br />
    <button @click="insertWord">插入一段话</button>
    <button @click="undo">撤销</button>
    <input v-model="replacementText" placeholder="输入替换内容" />
    <button @click="checkWordAndChange">取得选中的内容并替换</button>
    <button @click="findWordAndChange">模拟右侧抽屉替换</button>
    <input type="file" accept=".docx" @change="handleFileUpload" />
    <br />
    <button @click="insertMarkDown">模拟markdown数据</button>
    <button @click="exportMarkDown">导出markdown数据</button>
    <button @click="setAlignment('left')">靠左</button>
    <button @click="setAlignment('center')">居中</button>
    <button @click="setAlignment('right')">靠右</button>
    <div class="mainContent">
      <div class="toc-sidebar">
        <div
          v-for="item in tocItems"
          :key="item.id"
          :style="{ paddingLeft: (item.level - 2) * 20 + 'px' }"
          class="toc-item"
          @click="scrollToHeading(item.id)"
        >
          {{ item.text }}
        </div>
      </div>
      <div ref="editorElement" class="editorElement"></div>
    </div>
    <div v-if="tocHtml" class="toc-preview" v-html="tocHtml"></div>
  </div>
</template>

<script>
import { Editor } from "@tiptap/vue-2";
import StarterKit from "@tiptap/starter-kit";
import { Collaboration } from "@tiptap/extension-collaboration";
import { CollaborationCursor } from "@tiptap/extension-collaboration-cursor";
import * as Y from "yjs";
import { WebsocketProvider } from "y-websocket";
import TableRow from "@tiptap/extension-table-row";
import TableHeader from "@tiptap/extension-table-header";
// import mammoth from "mammoth/mammoth.browser";
import draggableImage from "./js/draggable-image";
import { CellSelection } from "prosemirror-tables";
import { markdownData } from "./js/markdown.js";
// import { TextSelection } from "prosemirror-state";
import { convertDocxToHTML } from "./js/docxConverter.js";
import { Node } from '@tiptap/core';
import {
  TableCellMerge,
  HeadingWithId,
  CustomImage,
  // CustomTable,
  textAlign,
  tableCell,
  markDown,
  AlignableTable,
  textStyle,
  // CustomParagraph,
} from "./js/tipTapConfig.js";
export default {
  directives: { draggableImage },
  data() {
    return {
      tocHtml: null,
      editor: null,
      replacementText: "",
      isDragging: false,
      initialX: 0,
      initialY: 0,
      offsetX: 0,
      offsetY: 0,
      tocItems: [],
      styleMap: {},
    };
  },

  mounted() {
    this.initializeEditor();
    // // 测试直接插入图片
    // this.editor.commands.setContent(
    // );
  },
  computed: {
    canDeleteRow() {
      return this.isInTable && this.editor.can().deleteRow();
    },

    canDeleteColumn() {
      return this.isInTable && this.editor.can().deleteColumn();
    },

    isInTable() {
      return this.editor?.isActive("table");
    },
  },
  beforeDestroy() {
    this.editor.destroy();
  },

  methods: {
    initializeEditor() {
      // 创建 Yjs 文档
      const ydoc = new Y.Doc();
      // 创建 WebSocket 提供者
      this.provider = new WebsocketProvider(
        "ws://localhost:1234",
        "room-name",
        ydoc
      );
      const CustomDiv = Node.create({
        name: "div", // 节点名称
        group: "block",
        content: "inline*", // 允许内容
        parseHTML() {
          return [{ tag: "div" }]; // 解析 HTML 中的 div 标签
        },
        addAttributes() {
          return {
            class: {
              default: null,
              parseHTML: (element) => element.getAttribute("class"), // 解析 class
            },
          };
        },
        renderHTML({ HTMLAttributes }) {
          return ["div", HTMLAttributes, 0]; // 渲染时保留 class
        },
      });
      this.editor = new Editor({
        element: this.$refs.editorElement,
        extensions: [
          StarterKit.configure({
            paragraph: {
              HTMLAttributes: {
                class: true,
              },
            },
            heading: {
              levels: [1, 2, 3, 4, 5], // 允许 h1-h4
              HTMLAttributes: {
                class: "my-heading",
              },
            },
          }),

          textAlign,
          // 关键修复 1：正确配置 Image 扩展
          CustomImage,
          // CustomParagraph,
          AlignableTable,
          // CustomTable,
          textStyle,
          TableRow,
          tableCell,
          TableHeader,
          TableCellMerge,
          HeadingWithId,
          markDown,
          // yjs协同
          Collaboration.configure({
            document: ydoc, // 绑定 Yjs 文档
          }),
          CollaborationCursor.configure({
            provider: this.provider, // 绑定 Yjs 提供者
            user: {
              name: "用户 " + Math.floor(Math.random() * 100), // 随机用户名
              color: "#" + Math.floor(Math.random() * 16777215).toString(16), // 随机颜色
            },
          }),
          CustomDiv,
        ],
        content: "<p>上传 Word 文档开始编辑...</p>",
        // 关键配置：启用 HTML 解析
        // parseOptions: {
        //   preserveWhitespace: "full",
        // },
      });
      this.editor.on("paste", ({ event }) => {
        this.handlePaste(event);
      });
      this.editor.on("update", () => {
        console.log("update======>");

        this.$nextTick(() => this.updateToc());
      });
      // 确保在编辑器内容更新后绑定事件
      this.editor.on("transaction", () => {
        // this.updateToc();
      });
    },
    async handleFileUpload(event) {
      const file = event.target.files[0];
      if (!file) return;
      try {
        const arrayBuffer = await this.readFile(file);
        // 关键修复 2：配置 mammoth 图片转换
        // 解析样式和内容
        const { value: html } = await mammoth.convertToHtml(
          { arrayBuffer },
          {
            styleMap: this.getStyleMap(),
            convertImage: mammoth.images.imgElement(async (image) => {
              const buffer = await image.read();
              const base64 = buffer.toString("base64");

              return {
                src: `data:${image.contentType};base64,${base64}`,
                style: `width: 100%; height: auto`,
              };
            }),
            transformDocument: mammoth.transforms.paragraph(
              this.transformParagraph
            ),
          }
        );
      this.editor.commands.setContent(html);
        console.log(" mammoth===", mammoth);

        // const { value: html } = await mammoth.convertToHtml(
        //   { arrayBuffer },
        //   {
        //     styleMap: [
        //       "p[style-name='Heading 1'] => h1:fresh",
        //       "p[style-name='Heading 2'] => h2:fresh",
        //       "r[style-name='Strong'] => strong",
        //     ],
        //     convertImage: mammoth.images.imgElement(async (image) => {
        //       const buffer = await image.read();
        //       const base64 = buffer.toString("base64");

        //       return {
        //         src: `data:${image.contentType};base64,${base64}`,
        //         style: `width: 100%; height: auto`,
        //       };
        //     }),
        //   }
        // );
        // 核心修复：先清空内容再重新设置
        // this.editor.commands.clearContent();
        // await this.$nextTick();
        // // 新增调试代码
        // this.editor.commands.setContent(html);

        console.log("编辑器内容树:", this.editor.getJSON());
        // document.getElementById("raw-html").innerText = html; // 用于页面展示
        // console.log(processedHtml, "processedHtmlprocessedHtml");
      } catch (error) {
        console.error("文档转换失败:", error);
      }
      try {
        const html = await convertDocxToHTML(file)
        console.log('test-gtml-==',html)
        this.tocHtml = this.extractToc(html)
         this.editor.commands.setContent(html);
      } catch (err) {
        console.error('转换失败:', err)
      }
    },
    // 提取目录部分
    extractToc(html) {
      const parser = new DOMParser();
      const doc = parser.parseFromString(html, "text/html");

      // 通过 class 选择所有目录项
      const tocItems = doc.querySelectorAll(
        ".toc-level-1, .toc-level-2, .toc-level-3"
      );
      return Array.from(tocItems)
        .map((item) => item.outerHTML)
        .join("");
    },
    // 读取文件为ArrayBuffer
    readFile(file) {
      return new Promise((resolve) => {
        const reader = new FileReader();
        reader.onload = () => resolve(reader.result);
        reader.readAsArrayBuffer(file);
      });
    },
    // 生成Mammoth样式映射
    getStyleMap() {
      return [
        "p[style-name='Heading 1'] => h3:fresh",
        "p[style-name='Heading 2'] => h2.bb",
        "p[style-name='toc 3'] => h4.abc",
        "p[style-name='Heading 1'] => h1.title",
        "r[style-name='Strong'] => strong.bold-text",
      ];
    },
    transformParagraph(element) {
      console.log(element, "elementelement");
      if (element.type === "paragraph") {
        let fontSize = element?.children?.[0]?.fontSize || "";
        let styleName = "";
        if (fontSize == "42" && !element.styleName) {
          // styleName = "Heading 1";
        }
        console.log(styleName, "styleNamestyleName", fontSize);
        return {
          ...element,
          class: `top-item`,
          styleName: element.styleName ? element.styleName : styleName,
          // attributes: {
          //   style: `fontSize: ${element?.children?.[0]?.fontSize}pt;`,
          // },
        };
      }
      return element;
    },
    calculateFontSize(element) {
      // 处理 Word 的 pt 单位转换（1pt ≈ 1.333px）
      const ptSize = element.style?.fontSize?.match(/\d+/)?.[0];
      return ptSize ? Math.round(ptSize * 1.333) : 16;
    },
    // 绑定图片
    bindDragHandlers() {
      document.querySelectorAll(".resizable-image").forEach((img) => {
        if (img._bound) return;
        img._bound = true;

        this.$directives.draggableImage.bind(img, {
          value: {
            updateAttributes: (attrs) => {
              this.editor.commands.updateAttributes("image", attrs);
            },
          },
        });
      });
    },
    // ✅ 处理粘贴事件
    async handlePaste(event) {
      const items = event.clipboardData.items;
      for (const item of items) {
        if (item.type.startsWith("image")) {
          event.preventDefault();
          const blob = item.getAsFile();
          const base64 = await this.blobToBase64(blob);
          this.insertImage(base64);
          return;
        }
      }
    },
    // ✅ Blob 转 Base64
    blobToBase64(blob) {
      return new Promise((resolve) => {
        const reader = new FileReader();
        reader.onload = () => resolve(reader.result);
        reader.readAsDataURL(blob);
      });
    },

    // ✅ 插入图片到编辑器
    insertImage(src) {
      this.editor
        .chain()
        .focus()
        .insertContent({
          type: "image",
          attrs: {
            src,
            width: "300px",
            height: "auto",
          },
        })
        .run();
    },
    // 插入文字
    insertWord() {
      this.editor.chain().focus().insertContent("插入一段话············").run();
    },
    // 撤回上次操作
    undo() {
      this.editor.chain().focus().undo().run();
    },
    // 选中文字并替换
    checkWordAndChange() {
      if (!this.editor.state.selection.empty) {
        // this.editor
        //   .chain()
        //   .focus() // 保持焦点
        //   .deleteSelection() // 删除选中内容
        //   .insertContent(this.replacementText) // 插入新内容
        //   .run();
        const { state } = this.editor;
        const { from, to } = state.selection;

        if (from === to) return;

        const textNode = state.schema.text(
          this.replacementText,
          state.selection.$head.marks() // 获取光标位置格式
        );

        const tr = state.tr.replaceWith(from, to, textNode);
        this.editor.view.dispatch(tr);
      } else {
        alert("请先选中要替换的文本");
      }
    },
    // 模拟右侧抽屉段落替换
    findWordAndChange() {
      const { state } = this.editor;
      const { doc } = state;
      let findText = this.replacementText;
      let replaceText = "替换后";
      let offset = 0;
      // 遍历文档中的所有节点，找到所有文本节点
      // 遍历文档中的所有节点
      doc.descendants((node, pos) => {
        console.log(node, "node");

        if (node.isText) {
          const text = node.text;
          let index = text.indexOf(findText);
          while (index !== -1) {
            const from = pos + index + offset;
            const to = from + findText.length;
            // 执行替换操作
            this.editor
              .chain()
              .focus()
              .deleteRange({ from, to })
              .insertContentAt(from, replaceText)
              .run();

            // 更新偏移量，考虑替换文本的长度
            offset += replaceText.length - findText.length;
            // 继续查找下一个匹配项
            index = text.indexOf(findText, index + 1);
          }
        }
        return true;
      });
    },
    // 插入表格
    insertTable(rows, cols) {
      this.editor
        .chain()
        .focus()
        .insertTable({ rows, cols, withHeaderRow: false })
        .run();
    },
    // 获取选中表格
    getSelectedCells(selection) {
      if (selection instanceof CellSelection) {
        const cells = [];
        selection.forEach((node, pos) => {
          if (["table_cell", "table_header"].includes(node.type.name)) {
            cells.push({ node, pos: pos + 1 });
          }
        });
        return { cells };
      }
      return null;
    },
    // 新增列
    addColumn() {
      this.editor.chain().focus().addColumnAfter().run();
    },
    addRow() {
      this.editor.chain().focus().addRowAfter().run();
    },
    deleteTable() {
      this.editor.chain().focus().deleteTable().run();
    },
    mergeCells() {
      this.editor.chain().focus().mergeCells().run();
    },

    splitCell() {
      this.editor.chain().focus().splitCell().run();
    },
    deleteRow() {
      this.editor.chain().focus().deleteRow().run();
    },

    deleteColumn() {
      this.editor.chain().focus().deleteColumn().run();
    },

    handleDragStart(event) {
      console.log("dragstart triggered");
      this.isDragging = true;
      this.initialX = event.clientX;
      this.initialY = event.clientY;
      this.offsetX = event.target.offsetLeft;
      this.offsetY = event.target.offsetTop;
      event.dataTransfer.effectAllowed = "move";
      event.dataTransfer.setData("text/html", event.target.outerHTML);
    },

    handleDragOver(event) {
      console.log("ssssss");
      if (this.isDragging && event.target.tagName === "TABLE") {
        event.preventDefault();
        const container = this.$refs.editorElement;
        const containerRect = container.getBoundingClientRect();
        const tableRect = event.target.getBoundingClientRect();

        const dx = event.clientX - this.initialX;
        const dy = event.clientY - this.initialY;

        let newX = this.offsetX + dx;
        let newY = this.offsetY + dy;

        // 边界检查
        if (newX < 0) {
          newX = 0;
        } else if (newX + tableRect.width > containerRect.width) {
          newX = containerRect.width - tableRect.width;
        }

        if (newY < 0) {
          newY = 0;
        } else if (newY + tableRect.height > containerRect.height) {
          newY = containerRect.height - tableRect.height;
        }

        event.target.style.left = newX + "px";
        event.target.style.top = newY + "px";
      }
    },

    handleDragEnd() {
      this.isDragging = false;
    },
    // 生成目录结构
    updateToc() {
      const headings = [];
      const transaction = this.editor.state.tr;

      // 遍历文档节点
      this.editor.state.doc.descendants((node, pos) => {
        if (node.type.name === "heading") {
          const id = this.generateID(node.textContent);

          // 添加锚点ID
          if (!node.attrs.id) {
            transaction.setNodeMarkup(pos, undefined, {
              ...node.attrs,
              id,
            });
          }

          headings.push({
            level: node.attrs.level,
            text: node.textContent,
            id: node.attrs.id || id,
          });
        }
      });

      // 提交事务更新节点属性
      transaction.setMeta("preventUpdate", true);
      this.editor.view.dispatch(transaction);

      this.tocItems = headings;
    },
    // 生成唯一ID
    generateID(text) {
      return text
        .toLowerCase()
        .replace(/[^a-z0-9]+/g, "-")
        .replace(/(^-|-$)/g, "");
    },
    // 滚动到对应标题
    scrollToHeading(id) {
      console.log(id, "id======>");

      const element = document.getElementById(id);
      if (element) {
        element.scrollIntoView({
          behavior: "smooth",
          block: "start",
        });
      }
    },
    // 导入Markdown数据
    insertMarkDown() {
      this.editor.commands.setContent(markdownData);
    },
    // 导出markdown数据
    exportMarkDown() {
      const markdownOutput = this.editor.storage.markdown.getMarkdown();
      console.log(markdownOutput);
    },
    async setAlignment(align) {
      console.log("ssss");

      console.log(this.editor.isActive("table"));
      // 统一处理所有元素对齐

      if (this.editor.isActive("image")) {
        this.editor.chain().focus().updateAttributes("image", { align }).run();
      } else if (this.editor.isActive("table")) {
        // let table = await this.getCurrentTable();
        console.log(this.editor.chain().focus(), "ttt");
        // table.parentNode.style.justifyContent = "center";
        this.editor.chain().focus().setTextAlign(align).run();
      } else {
        this.editor.chain().focus().setTextAlign(align).run();
      }
    },
    // 获取当前聚焦的完整表格
    getCurrentTable() {
      // 获取当前选区节点
      const { $from } = this.editor.state.selection;
      const currentNode = this.editor.view.nodeDOM($from.pos);

      // 向上遍历查找 table 元素
      if (currentNode) {
        const tableElement = currentNode.closest("table");
        return tableElement;
      }
      return null;
    },
    // scrollToHeading(pos) {
    //   const { view } = this.editor;
    //   const node = view.domAtPos(pos).node;

    //   if (node instanceof HTMLElement) {
    //     node.scrollIntoView({
    //       behavior: "smooth",
    //       block: "start",
    //     });

    //     // 添加临时高亮
    //     node.classList.add("highlight");
    //     setTimeout(() => node.classList.remove("highlight"), 1000);
    //     return;
    //   }
    //   console.warn("无法定位标题元素");
    // },
  },
};
</script>

<style scoped>
/* 组件样式 */
</style>

<style lang="scss">
.toc {
  display: block;
}
.mainContent {
  display: flex;
  .toc-sidebar {
    width: 20%;
    .toc-item {
      white-space: nowrap;
      text-align: left;
      text-overflow: ellipsis;
      overflow: hidden;
      cursor: pointer;
      margin: 4px 0;
    }
  }
  .editorElement {
    flex: 1;
  }
}
/* 全局文档样式 */
.doc-paragraph {
  margin: 12px 0;
  line-height: 1.6;
  font-family: "SimSun", serif;
}

/* 表格样式 */
table {
  border-collapse: collapse;
  margin: 1rem 0;
  table-layout: fixed;
  max-width: 100% !important;
}

td,
th {
  padding: 8px;
  min-width: 50px;
  position: relative;
  vertical-align: top;
}

th {
  font-weight: bold;
}

/* 合并单元格提示 */
[colspan]:not([colspan="1"]),
[rowspan]:not([rowspan="1"]) {
  background-color: #f0f8ff;
}

/* 列宽调整手柄 */
.column-resize-handle {
  position: absolute;
  right: 0;
  top: 0;
  bottom: 0;
  width: 4px;
  background-color: #adf;
  pointer-events: none;
  cursor: pointer;
}

img {
  max-width: 100%;
  height: auto;
  border: 1px solid red !important; /* 调试用边框 */
}
/* 全局样式或组件内样式 */
.editor-image {
  border: 1px solid #ddd !important; /* 调试用边框 */
}

/* 覆盖潜在冲突样式 */
.ProseMirror {
  width: 100%;
  img {
    max-wdith: 100% !important;
  }
  .tableWrapper {
    display: flex;
    align-items: center;
  }
  table {
    border-collapse: collapse;
    border: 1px solid #000;
    margin: 5px;
  }
  td,
  td {
    border: 1px solid #000; /* 边框颜色和粗细 */
    padding: 8px; /* 内边距 */
  }
}
/* ✅ 确保图片可见性 */
.resizable-image {
  display: block !important;
  max-width: 100%;
  height: auto;
  margin: 10px auto;
  position: relative !important;
}

.resizable-image::after {
  content: "";
  position: absolute;
  bottom: -8px;
  right: -8px;
  width: 16px;
  height: 16px;
  background: #2196f3;
  border-radius: 50%;
  cursor: nwse-resize;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
button {
  margin: 5px;
}

/* 统一对齐样式 */
.ProseMirror {
  p[data-text-align],
  h1[data-text-align],
  h2[data-text-align] {
    &[data-text-align="left"] {
      text-align: left;
    }
    &[data-text-align="center"] {
      text-align: center;
    }
    &[data-text-align="right"] {
      text-align: right;
    }
  }

  /* 图片浮动处理 */
  .float-image {
    max-width: 60%;
    &[data-align="left"] {
      float: left;
      margin: 0 1rem 1rem 0;
    }
    &[data-align="right"] {
      float: right;
      margin: 0 0 1rem 1rem;
    }
    &[data-align="center"] {
      display: block;
      margin: 1rem auto;
    }
  }
}

/* 清除浮动 */
.ProseMirror::after {
  content: "";
  display: table;
  clear: both;
}
</style>
